﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using System.Text.RegularExpressions;
using intelliEssay.Interop;
using intelliEssay.Interop.ParagraphStyle;
using intelliEssay.Core.DocumentStructure;

namespace intelliEssay.Checkers.Reference
{

    internal static class RegexConstants
    {
        public class RegexHelper
        {
            public readonly string Name;
            public readonly string EffectiveRegexContent;
            public readonly string GroupName;
            public RegexHelper(string displayName, string groupName, string regex)
            {
                Name = displayName;
                EffectiveRegexContent = "(?<" + groupName + ">" + regex + ")";
                GroupName = groupName;
            }
            public override string ToString()
            {
                return EffectiveRegexContent;
            }
        }

        const string Anything_NoneDot_NoMeaninglessSymbols = @"[\u4e00-\u9fa5a-zA-Z0-9\s\-\(\)（）\[\]+#—]{2,}";
        const string Anything_NoMeaninglessSymbols = @"[\u4e00-\u9fa5a-zA-Z0-9\s\-\(\)（）\[\]\.]{2,}";
        const string DigitsWS_None = "[^\\d\\s]+";
        const string Anything_NoneDigits_NoneMeaninglessSymbol = "[\u4e00-\u9fa5a-zA-Z\\s\\-,]{2,}";
        const string Digits_4 = "\\d{4}";
        const string WS_Any = "\\s*";
        const string Digits_Multiple = "\\d+";
        const string DigitsOrCharacters = "[0-9a-zA-Z\\s]+";
        const string Digits_Multiple_Indexed = "(\\[" + Digits_Multiple + "\\])";
        const string Digits_Multiple_Allow_WS = "\\s*\\d+\\s*";

        public static RegexHelper StartingWS = new RegexHelper("Starting Whitespaces", "startingWS", WS_Any);
        public static RegexHelper Author = new RegexHelper("Author", "author", Anything_NoneDigits_NoneMeaninglessSymbol);
        public static RegexHelper Title = new RegexHelper("Title", "title", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper PublicationName = new RegexHelper("Publication Name", "publicationName", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper YearOfPublish = new RegexHelper("Publish Year", "publishYear", Digits_4);
        public static RegexHelper StartingPage = new RegexHelper("Starting Page", "startingPage", Digits_Multiple_Allow_WS);
        public static RegexHelper TrailingWS = new RegexHelper("Trailing Whitespaces", "trailingWS", WS_Any);
        public static RegexHelper PublicationID = new RegexHelper("Publication ID", "publicationID", Anything_NoMeaninglessSymbols);
        public static RegexHelper EndingPage = new RegexHelper("Ending Page", "endingPage", Digits_Multiple_Allow_WS);
        public static RegexHelper PublishSite = new RegexHelper("Publish Site", "publishSite", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper PublisherName = new RegexHelper("Publisher", "publisher", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper In = new RegexHelper("In", "in", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper Compiler = new RegexHelper("Compiler", "compiler", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper CompiledCollectionTitle = new RegexHelper("Compiled Collection Title", "compiledCT", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper DegreeEssay = new RegexHelper("Degree Essay", "degreeEssay", "博士论文|硕士论文");
        public static RegexHelper GrantingEntity = new RegexHelper("Granting Entity", "grantingEntity", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper Nation = new RegexHelper("Nation", "nation", Anything_NoneDigits_NoneMeaninglessSymbol);
        public static RegexHelper Type = new RegexHelper("Type", "type", Anything_NoneDigits_NoneMeaninglessSymbol);
        public static RegexHelper ID = new RegexHelper("ID", "iD", Anything_NoMeaninglessSymbols);
        public static RegexHelper DateTime = new RegexHelper("Date time", "dateTime", Anything_NoneDot_NoMeaninglessSymbols);
        public static RegexHelper ReferenceIndex = new RegexHelper("Reference Index", "refIndx", Digits_Multiple_Indexed);
    }

    public class ReferenceChecker : intelliEssay.Core.IEssayChecker
    {
        static string[] referenceRegexes = new string[]
        {
           string.Format("^{0}({9}){{0,1}}\\s*{1}\\.\\s*{2}(\\.\\s*{3}){{0,1}}(,\\s*{4}){{0,1}}(,\\s*{5}){{0,1}}(:\\s*{6}[~\\-]{7}){{0,1}}\\.{8}$",RegexConstants.StartingWS,RegexConstants.Author,RegexConstants.Title,
           RegexConstants.PublicationName,RegexConstants.YearOfPublish,RegexConstants.PublicationID,RegexConstants.StartingPage,RegexConstants.EndingPage,RegexConstants.TrailingWS,RegexConstants.ReferenceIndex),
          
           string.Format("^{0}({9}){{0,1}}\\s*{1}\\.\\s*{2}(\\.\\s*{3}){{0,1}}(:\\s*{4}){{0,1}}(,\\s*{5}){{0,1}}(,\\s*{6}[~\\-]{7}){{0,1}}\\.{8}$",RegexConstants.StartingWS, RegexConstants.Author,RegexConstants.PublicationName,RegexConstants.PublishSite,RegexConstants.PublisherName,
           RegexConstants.YearOfPublish,RegexConstants.StartingPage,RegexConstants.EndingPage,RegexConstants.TrailingWS,RegexConstants.ReferenceIndex),
           
           string.Format("^{0}({12}){{0,1}}\\s*{1}\\.\\s*{2}(\\.\\s*{3}){{0,1}}(:\\s*{4}){{0,1}}(,\\s*{5}){{0,1}}(\\.\\s*{6}){{0,1}}(:\\s*{7}){{0,1}}(\\.\\s*{8}){{0,1}}(,\\s*{9}[~\\-]{10}){{0,1}}\\.{11}$",RegexConstants.StartingWS,RegexConstants.Author,RegexConstants.Title,RegexConstants.In,RegexConstants.Compiler,RegexConstants.CompiledCollectionTitle,
           RegexConstants.PublishSite,RegexConstants.PublisherName,RegexConstants.YearOfPublish,RegexConstants.StartingPage,RegexConstants.EndingPage,RegexConstants.TrailingWS,RegexConstants.ReferenceIndex),
          
           string.Format("^{0}({7}){{0,1}}\\s*{1}\\.\\s*{2}(:\\s*\\[{3}\\]){{0,1}}(\\.\\s*{4}){{0,1}}(,\\s*{5}){{0,1}}\\.{6}$",RegexConstants.StartingWS,RegexConstants.Author,RegexConstants.Title,RegexConstants.DegreeEssay,RegexConstants.GrantingEntity,RegexConstants.YearOfPublish,RegexConstants.TrailingWS,RegexConstants.ReferenceIndex),
         
           string.Format("^{0}({8}){{0,1}}\\s*{1}\\.\\s*{2}(\\.\\s*{3}){{0,1}}(\\.\\s*{4}){{0,1}}(\\.\\s*{5}){{0,1}}(,\\s*{6}){{0,1}}\\.{7}$",RegexConstants.StartingWS, RegexConstants.Author,RegexConstants.Title,RegexConstants.Nation,RegexConstants.Type,RegexConstants.ID,RegexConstants.YearOfPublish,RegexConstants.TrailingWS,RegexConstants.ReferenceIndex),
        
           string.Format("^{0}({8}){{0,1}}\\s*{1}\\.\\s*({2}){{0,1}}\\.\\s*{3}(\\.\\s*{4}){{0,1}}(:\\s*{5}){{0,1}}(,\\s*{6}){{0,1}}\\.{7}$",RegexConstants.StartingWS, RegexConstants.GrantingEntity,RegexConstants.ID,RegexConstants.Title,RegexConstants.PublishSite,RegexConstants.PublisherName,RegexConstants.YearOfPublish,RegexConstants.TrailingWS,RegexConstants.ReferenceIndex),
        
           string.Format("^{0}({9}){{0,1}}\\s*{1}\\.\\s*{2}(\\.\\s*{3}){{0,1}}(,\\s*{4}){{0,1}}(,\\s*{5}){{0,1}}(,\\s*{6}[~\\-]{7}){{0,1}}\\.{8}$", RegexConstants.StartingWS, RegexConstants.Author, RegexConstants.Title, RegexConstants.PublisherName, RegexConstants.YearOfPublish, RegexConstants.PublicationID, RegexConstants.StartingPage, RegexConstants.EndingPage, RegexConstants.TrailingWS, RegexConstants.ReferenceIndex),                  
           string.Format("^{0}({6}){{0,1}}\\s*{1}\\.\\s*{2}(\\.\\s*{3}){{0,1}}(,\\s*{4}){{0,1}}\\.{5}$",RegexConstants.StartingWS,RegexConstants.Author,RegexConstants.Title, RegexConstants.PublicationName,RegexConstants.PublicationID,RegexConstants.TrailingWS,RegexConstants.ReferenceIndex),
        
           string.Format("^{0}({7}){{0,1}}\\s*{1}\\.\\s*{2}(\\.\\s*{3}){{0,1}}(,\\s*{4}){{0,1}}(,\\s*{5}){{0,1}}\\.{6}$",RegexConstants.StartingWS, RegexConstants.Author,RegexConstants.Title,RegexConstants.PublicationName,RegexConstants.YearOfPublish,RegexConstants.PublicationID,RegexConstants.TrailingWS,RegexConstants.ReferenceIndex)
        };

        static string[] referenceRegexNames = new string[]
        {
            "连续参考物","专（译）著","论文集","学位论文","专利","技术标准","图书","期刊","报纸"
        };

        public void Run(Core.Task task)
        {
            var referenceList = task.documentStructure.ReferencedDocuments;
            var referenceTitle = task.documentStructure.Reference;
            if (referenceTitle == null)
            {
                return;
            }
            var runs = referenceTitle.Elements<Run>();
            Paragraph standard = intelliEssay.Core.DocumentStructure.StandardFormats.GetStandardFormatByDocumentPart(Core.DocumentStructure.DocumentParts.Reference, 0, task);




            foreach (Run r in runs)
            {
                if (r.InnerText.Trim() == "")
                    continue;
                RunInfoEx rinfo = new RunInfoEx(task.TaskObjectRoot, r, task.taskSetting.hostApp);


                Run standardRun = standard.Elements<Run>().First<Run>();
                RunInfoEx standardRInfo = new RunInfoEx(task.TaskObjectRoot, standardRun, task.taskSetting.hostApp);
                StringValue fS = rinfo["FontSize"];
                StringValue suggestedFS = standardRInfo["FontSize"];
                string rf = rinfo["runfonts"];
                string suggestedRF = standardRInfo["runfonts"];
                if (fS.Value != suggestedFS.Value)
                {
                    task.AddEssayExceptionToEssayExceptionCollection(new Core.EssayException(Core.ExceptionType.Font, "参考文献字号为" + (int.Parse(suggestedFS.Value) / 2), r, task, true));
                }
                if (rf != suggestedRF)
                {
                    task.AddEssayExceptionToEssayExceptionCollection(new Core.EssayException(Core.ExceptionType.Font, "参考文献字体为" + suggestedRF, r, task, true));
                }
            }
            double indentLeft = DocumentAlignmentHelper.QParagraphEffectiveLeftIndentationInMilimeter(referenceTitle, task.TaskObjectRoot, task.taskSetting.paperWidth, true, task.taskSetting.hostApp);
            double suggestedIndent = DocumentAlignmentHelper.QParagraphEffectiveLeftIndentationInMilimeter(referenceTitle, task.TaskObjectRoot, task.taskSetting.paperWidth, true, task.taskSetting.hostApp);
            if (Math.Abs(indentLeft - suggestedIndent) > 0)
            {
                task.AddEssayExceptionToEssayExceptionCollection(new Core.EssayException(Core.ExceptionType.Font, "参考文献左缩进为" + suggestedIndent + "毫米", standard, task, true));
            }
            int LastRefIdx = -1;
            for (int l = 0; l < referenceList.Count; l++)
            {
                bool currentSuccess = false;
                bool[] SkipBitMask = new bool[referenceRegexes.Length];
                for (int i = 0; i < referenceRegexes.Length; i++)
                {
                    if (SkipBitMask[i])
                    {
                        continue;
                    }
                    Regex regex = new Regex(referenceRegexes[i], RegexOptions.Compiled);
                    Match match = regex.Match(referenceList[l].InnerText);
                    if (match.Success)
                    {
                        currentSuccess = true;
                        string matchedAuthors = match.Groups["author"].Value;
                        var authors = (matchedAuthors).Split(',');
                        if (matchedAuthors != "")
                        {
                            foreach (var author in authors)
                            {
                                if (author.Trim().Length == 0 || author.Trim().Split(' ').Length >= 4)
                                {
                                    currentSuccess = false;
                                    break;
                                }
                            }
                        }
                        if (currentSuccess)
                        {
                            break;
                        }
                        else
                        {
                            SkipBitMask[i] = true;
                            i = 0;

                        }
                    }
                }
                if (currentSuccess == false)
                {
                    var currentXception = new Core.EssayException(Core.ExceptionType.Reference, "参考引用格式错误。", referenceList[l], task, true);
                    task.AddEssayExceptionToEssayExceptionCollection(currentXception);
                }
            }
        }

        public void Cancel(Core.Task task)
        {

        }

        public string GetDescription(string cultureInfo)
        {
            return "Checks reference content formats, while ignoring alignments and fonts";
        }

        public string GetName(string cultureInfo)
        {
            return "Reference Checker";
        }
    }
}
